﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProgNetComponents.ExtenderProviders;
using ProgNetDxComponents.ExtenderProviders.Settings;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Repository;
using System.ComponentModel;
using ProgNetDxComponents.ExtenderProviders.Browsers;
using System.Data;
using System.Windows.Forms;
using DevExpress.XtraEditors.Controls;

namespace ProgNetDxComponents.ExtenderProviders
{
    public class BrowserProvider : BaseExtenderProvider<BrowserSettings>
    {
        public BrowserProvider(IContainer c) : base(c) { }
        public BrowserProvider() { }
        protected override void ProcessObject(object sender, BrowserSettings settings)
        {
            if (settings != null)
            {
                RepositoryItemTextEdit rep = null;
                if (sender is RepositoryItemTextEdit)
                {
                    rep = (sender as RepositoryItemTextEdit);
                    rep.Tag = rep;
                }
                if (sender is TextEdit)
                    rep = (sender as TextEdit).Properties;

                PrepareEdit(rep, settings);
            }
        }
        private void PrepareEdit(RepositoryItemTextEdit edit, BrowserSettings s)
        {
            RepositoryItemLookUpEditBase rep = null;
            if (edit is RepositoryItemLookUpEditBase)
                rep = (edit as RepositoryItemLookUpEditBase);
            if (rep != null)
            {
                AssignBrowser(rep, s.Browser, s.BrowserDisplayFilter);
                CreateLookupColumns(rep as RepositoryItemLookUpEdit, s.Browser);
            }
            SetAdditionalBrowser(edit, s);
        }

        #region Additional Browser
        private void SetAdditionalBrowser(RepositoryItemTextEdit edit, BrowserSettings s)
        {
            RepositoryItemButtonEdit buttonEdit = (edit as RepositoryItemButtonEdit);
            EditorButton button = null;
            edit.KeyDown -= new KeyEventHandler(edit_KeyDown);
            edit.CustomDisplayText -= new CustomDisplayTextEventHandler(edit_CustomDisplayText);
            edit.FormatEditValue -= new ConvertEditValueEventHandler(edit_FormatEditValue);
            if (buttonEdit != null)
            {
                foreach (EditorButton btn in buttonEdit.Buttons)
                {
                    if (btn.Tag == s)
                    {
                        button = btn;
                        break;
                    }
                }
            }

            if (s.AdditionalBrowser != null)
            {
                LookUpEdit lue = s.AdditionalLookup;
                if (lue == null)
                {
                    lue = new LookUpEdit();
                    lue.Tag = s;
                    s.SetFieldValue("_AdditionalLookup", lue);
                    lue.Properties.AutoHeight = false;
                    lue.Height = 0;
                    lue.Dock = DockStyle.Bottom;
                    lue.EditValueChanging += new ChangingEventHandler(lue_EditValueChanging);
                    lue.EditValueChanged += new EventHandler(lue_EditValueChanged);
                    lue.TabStop = false;
                }
                CreateLookupColumns(lue.Properties, s.AdditionalBrowser);
                AssignBrowser(lue.Properties, s.AdditionalBrowser, s.AdditionalBrowserDisplayFilter);

                edit.FormatEditValue += new ConvertEditValueEventHandler(edit_FormatEditValue);
                edit.CustomDisplayText += new CustomDisplayTextEventHandler(edit_CustomDisplayText);
                edit.KeyDown += new KeyEventHandler(edit_KeyDown);
                if (buttonEdit != null)
                {
                    if (button == null)
                        buttonEdit.Buttons.Add(new EditorButton(s, ButtonPredefines.Plus));

                    buttonEdit.ButtonClick -= new ButtonPressedEventHandler(buttonEdit_ButtonClick);
                    buttonEdit.ButtonClick += new ButtonPressedEventHandler(buttonEdit_ButtonClick);
                }
            }
            else
            {
                if (buttonEdit != null)
                {
                    if (button != null)
                    {
                        buttonEdit.Buttons.RemoveAt(buttonEdit.Buttons.IndexOf(button));
                    }
                }
                s.SetFieldValue("_AdditionalLookup", null);
            }
        }
        void lue_EditValueChanging(object sender, ChangingEventArgs e)
        {
            LookUpEdit lue = sender as LookUpEdit;

            BrowserSettings s = lue.Tag as BrowserSettings;
            if (s != null)
            {
                s.OnAdditionalBrowserValueChanging(lue.Parent, e);
            }
        }

        void edit_FormatEditValue(object sender, ConvertEditValueEventArgs e)
        {
            //BaseEdit edit = sender as BaseEdit;
            //BrowserSettings s = null;
            //if (edit != null)
            //{
            //    if (_AllSettings.ContainsKey(sender))
            //        s = _AllSettings[sender];
            //    else
            //    {
            //        object o = GetRealKey(edit.Properties);
            //        if (o != null && _AllSettings.ContainsKey(o))
            //            s = _AllSettings[o];
            //    }
            //}
            //else
            //{
            //    object o = GetRealKey(sender);
            //    if (o != null && _AllSettings.ContainsKey(o))
            //        s = _AllSettings[o];
            //}

            //if (s != null && s.AdditionalLookup != null)
            //{
            //    object ob = edit != null ? edit.EditValue : e.Value;
            //    if (ob != null)
            //    {
            //        ob = s.AdditionalLookup.Properties.GetDisplayValueByKeyValue(ob);
            //    }
            //    if (ob != null)
            //    {
            //        e.Value = ob.ToString();
            //        e.Handled = true;
            //    }
            //}
        }

        void edit_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
        {
            //BaseEdit edit = sender as BaseEdit;
            //BrowserSettings s = null;
            //if (edit != null)
            //{
            //    if (_AllSettings.ContainsKey(edit))
            //        s = _AllSettings[edit];
            //    else
            //    {
            //        object o = GetRealKey(edit.Properties);
            //        if (o != null && _AllSettings.ContainsKey(o))
            //            s = _AllSettings[o];
            //    }
            //}
            //else
            //{
            //    object o = GetRealKey(sender);
            //    if (o != null && _AllSettings.ContainsKey(o))
            //        s = _AllSettings[o];
            //}
            //if (s != null && s.AdditionalLookup != null)
            //{
            //    object ob = edit != null ? edit.EditValue : e.Value;
            //    if (ob != null)
            //    {
            //        ob = s.AdditionalLookup.Properties.GetDisplayValueByKeyValue(ob);
            //    }
            //    if (ob != null)
            //        e.DisplayText = ob.ToString();
            //}
        }

        private void edit_KeyDown(object sender, KeyEventArgs e)
        {
            ShowAdditionalPopup(sender, e, null);
        }
        private void ShowAdditionalPopup(object sender, KeyEventArgs e, EditorButton button)
        {
            BaseEdit edit = sender as BaseEdit;
            BrowserSettings s = null;
            if (!edit.Properties.ReadOnly)
            {
                if (_AllSettings.ContainsKey(edit))
                    s = _AllSettings[edit];
                else
                {
                    object o = GetRealKey(edit.Properties);
                    if (o != null && _AllSettings.ContainsKey(o))
                        s = _AllSettings[o];
                }

                if (s != null && s.AdditionalBrowser != null &&
                    !edit.Properties.ReadOnly)
                {
                    bool show = e == null && button != null && button.Tag is BrowserSettings;
                    show |= button == null && e != null && e.KeyCode == s.AdditionalBrowserPopupKey;

                    if (show)
                    {
                        Control c = s.AdditionalLookup.Parent;
                        if (c != null)
                            c.Controls.Remove(s.AdditionalLookup);

                        edit.Controls.Add(s.AdditionalLookup);
                        s.AdditionalLookup.Properties.LockEvents();
                        s.AdditionalLookup.EditValue = edit.EditValue;
                        s.AdditionalLookup.Properties.UnLockEvents();
                        s.AdditionalLookup.ShowPopup();
                    }
                }
            }
        }

        void lue_EditValueChanged(object sender, EventArgs e)
        {
            LookUpEdit lue = sender as LookUpEdit;
            BaseEdit edit = lue.Parent as BaseEdit;
            if (edit != null)
            {
                edit.EditValue = lue.EditValue;
                Form f = edit.FindForm();
                if (f != null)
                {
                    f.SelectNextControl(edit, true, true, false, true);
                }
                edit.Focus();
            }
            BrowserSettings s = lue.Tag as BrowserSettings;
            if (s != null)
            {
                s.OnAdditionalBrowserValueChanged(edit);
            }
        }

        void buttonEdit_ButtonClick(object sender, ButtonPressedEventArgs e)
        {
            ShowAdditionalPopup(sender, null, e.Button);
        }
        #endregion
        private void CreateLookupColumns(RepositoryItemLookUpEdit rep, Browser browser)
        {
            if (rep != null)
            {
                rep.BeginInit();
                rep.QueryPopUp -= new CancelEventHandler(rep_QueryPopUp);
                rep.Popup -= new EventHandler(rep_Popup);
                rep.Columns.Clear();
                
                if (browser != null)
                {
                    rep.QueryPopUp += new CancelEventHandler(rep_QueryPopUp);
                    rep.Popup += new EventHandler(rep_Popup);
                    BrowserDisplayType type = browser.DisplayType;
                    if(type == BrowserDisplayType.ConfigSpecified)
                        type = BrowserCache.GetBrowserDisplayTypeFormConfig(browser.Name);
                    if (type == BrowserDisplayType.ComboLookUp)
                    {
                        rep.Columns.Add(BrowserTools.CreateColumn(browser.Columns[browser.DisplayMember]));
                    }
                    else
                    {
                        foreach (BrowserColumn col in browser.Columns)
                        {
                            rep.Columns.Add(BrowserTools.CreateColumn(col));
                        }
                    }
                }
                rep.EndInit();
            }
        }
        private void AssignBrowser(RepositoryItemLookUpEditBase rep, Browser browser, string filter)
        {
            if (browser != null)
            {
                DataView dv = new DataView(BrowserCache.GetBrowserData(browser.Name));
                dv.RowFilter = filter;
                rep.DataSource = dv;
                rep.ValueMember = browser.ValueMember.ToUpper();
                rep.DisplayMember = browser.DisplayMember.ToUpper();
            }
            else
            {
                rep.DataSource = null;
                rep.ValueMember = null;
                rep.DisplayMember = null;
            }
        }
        private void rep_Popup(object sender, EventArgs e)
        {
            LookUpEdit edit = sender as LookUpEdit;
            BrowserSettings s = null;
            Browser b = null;
            if (edit != null)
            {
                if (edit.Tag != null && edit.Tag is BrowserSettings)
                {
                    s = edit.Tag as BrowserSettings;
                    b = s.AdditionalBrowser;
                }
                else
                {
                    if (_AllSettings.ContainsKey(edit))
                        s = _AllSettings[edit];
                    else
                    {
                        object o = GetRealKey(edit.Properties);
                        if (o != null && _AllSettings.ContainsKey(o))
                            s = _AllSettings[o];
                    }
                    if (s != null)
                        b = s.Browser;
                }
            }

            if (s != null)
            {
                object popupForm = edit.GetFieldValue("_popupForm");
                if (popupForm != null)
                {
                    object painter = popupForm.GetFieldValue("fPainter");
                    LookUpEditCustomPainter fPainter = painter as LookUpEditCustomPainter;
                    if (fPainter == null)
                    {
                        fPainter = new LookUpEditCustomPainter();
                        popupForm.SetFieldValue("fPainter", fPainter);
                        fPainter.Browser = b;
                        edit.ClosePopup();
                        edit.ShowPopup();
                        return;
                    }
                    if (fPainter != null)
                        fPainter.Browser = b;
                }
            }
        }

        void rep_QueryPopUp(object sender, CancelEventArgs e)
        {
            LookUpEdit edit = sender as LookUpEdit;
            BrowserSettings s = null;
            Browser b = null;
            bool additional = false;

            if (edit != null)
            {
                if (edit.Tag != null && edit.Tag is BrowserSettings)
                {
                    s = edit.Tag as BrowserSettings;
                    b = s.AdditionalBrowser;
                    additional = true;
                }
                else
                {
                    if (this._AllSettings.ContainsKey(edit))
                        s = _AllSettings[edit];
                    else
                    {
                        object o = GetRealKey(edit.Properties);
                        if (o != null && _AllSettings.ContainsKey(o))
                            s = _AllSettings[o];
                    }
                    if (s != null)
                        b = s.Browser;
                }

                if (s != null && b != null)
                {
                    BrowserDisplayType type = b.DisplayType;// GetDisplayType(s, additional);

                    if (type == BrowserDisplayType.Dialog)
                    {
                        e.Cancel = true;
                        if (!edit.Properties.ReadOnly)
                        {
                            ObjectDialogResult dlg = b.ShowDialog(edit.EditValue,  false, additional ? s.AdditionalBrowserDisplayFilter : s.BrowserDisplayFilter);
                            if (dlg.DialogResult == DialogResult.OK)
                                edit.EditValue = dlg.Value;
                        }
                    }
                }
            }
        }

        protected override object GetRealKey(object target)
        {
            if (target is RepositoryItem &&
                (target as RepositoryItem).Tag != null &&
                (target as RepositoryItem).Tag is RepositoryItem)
                return (target as RepositoryItem).Tag as RepositoryItem;

            return target;
        }

        public override bool CanExtend(object extendee)
        {
            if (extendee is TextEdit ||
                extendee is RepositoryItemTextEdit)
            {
                return true;
            }
            return false;
        }
    }
}
